// 标签属性 
var attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/;
var unicodeRegExp = /a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD/;
// 标签名称 
var ncname = "[a-zA-Z_][\\-\\.0-9_a-zA-Z" + (unicodeRegExp.source) + "]*";
// <span:xx>
var qnameCapture = "((?:" + ncname + "\\:)?" + ncname + ")";
// 开始标签 获取标签名 < 
var startTagOpen = new RegExp(("^<" + qnameCapture));
// 匹配开始标签的结束 >
var startTagClose = /^\s*(\/?)>/;
// 匹配结束标签 </div>
var endTag = new RegExp(("^<\\/" + qnameCapture + "[^>]*>"));

// 创建AST语法树
function createASTElement(tag, attrs){
  return {
    tag, // 当前元素
    attrs, // 当前元素属性
    children: [], // 子元素
    type: 1, // 节点类型
    parent: null // 父节点
  }
}

let root; // 根元素
let createParent; // 当前的元素的父元素
// 模拟栈的数据结构的先入后出的处理元素
let stack = [];
function start(tag, attrs){ // 开始标签
  const element = createASTElement(tag, attrs);
  if(!root){
    root = element;
  }
  createParent = element;
  stack.push(element); // 入栈
}
function matchs(text){ // 文本
  // 替换掉文本中的所有空格 换行符
  text = text.replace(/\s|\n/g, '');
  if(text){
    createParent.children.push({
      type: 3,
      text
    })
  }
}
function end(tag){ // 结束标签
  const element = stack.pop(); // 出栈
  createParent = stack[stack.length - 1]; // 上一步已经删除了当前元素  所以现在的元素就是之前的倒数第二位元素  那么他的父元素就是倒数第三位
  if(createParent){
    element.parent = createParent.tag; // 设置当前元素的父元素
    createParent.children.push(element); // 将当前元素添加到父元素的children中
  }
}

export default function(html) {
  while (html) { // 不停循环直到解析完第一层dom
    // 首先以标签为分界线处理
    let textEnd = html.indexOf('<');
    if(textEnd === 0){ // 解析到此处 遇到了标签
      // 开始标签
      const startTagMatch = parseStartTag();
      if(startTagMatch){
        start(startTagMatch.tagName, startTagMatch.attrs);
      }
      // 结束标签
      const endTagMatch = html.match(endTag);
      // 删除结束标签
      if(endTagMatch){
        advance(endTagMatch[0].length);
        end(endTagMatch[1]);
        continue;
      }
    }
    // 文本
    let text
    if(textEnd > 0){
      // 获取全部文本内容
      text = html.slice(0, textEnd);
    }
    // 删除文本
    if(text){ 
      advance(text.length);
      matchs(text);
    }
  }
  // 返回开始标签的标签名和属性及属性值
  function parseStartTag(){
    const start = html.match(startTagOpen); // 检测是否是开始标签 如果不是则返回null
    if(start){
      let match = {
        tagName: start[1],
        attrs: []
      }
      // 删除开始标签的<和标签名 没有删除属性和>
      advance(start[0].length);
      // 开始拿标签属性
      let attr;
      let endArr;
      while (!(endArr = html.match(startTagClose)) && (attr = html.match(attribute))) {
        // 存在标签属性
        match.attrs.push({
          name: attr[1],
          value: attr[3]||attr[4]||attr[5] // 4 和 5 其他的属性会保存再此处
        })
        advance(attr[0].length);
      }
    
      // 标签的闭合符号 >
      if(endArr){
        advance(endArr[0].length);
        return match;
      }
    }
  }
  // 当前用到的部分删除 使之继续往后走
  function advance(index){
    html = html.slice(index);
  }

  return root;
}